<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta http-equiv="Content-Language" content="zh-CN"><link href="stylesheet.css" media="all" rel="stylesheet" type="text/css">
<title>分析器阶段</title>
<script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?d286c55b63a3c54a1e43d10d4c203e75"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script>
</head><body class="SECT1">
<div>
<table summary="Header navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><th colspan="5" align="center" valign="bottom">PostgreSQL 8.2.3 中文文档</th></tr>
<tr><td width="10%" align="left" valign="top"><a href="connect-estab.html" accesskey="P">后退</a></td><td width="10%" align="left" valign="top"><a href="overview.html">快退</a></td><td width="60%" align="center" valign="bottom">章42. PostgreSQL 内部概貌</td><td width="10%" align="right" valign="top"><a href="overview.html">快进</a></td><td width="10%" align="right" valign="top"><a href="rule-system.html" accesskey="N">前进</a></td></tr>
</table>
<hr align="LEFT" width="100%"></div>
<div class="SECT1"><h1 class="SECT1"><a name="PARSER-STAGE">42.3. 分析器阶段</a></h1>
<p><i class="FIRSTTERM">分析器阶段</i>含两个部分：</p>
<ul>
<li><p>在 <tt class="FILENAME">gram.y</tt> 和 <tt class="FILENAME">scan.l</tt> 里定义的<i class="FIRSTTERM">分析器</i>是使用 Unix 工具 <span class="APPLICATION">yacc</span> 和 <span class="APPLICATION">lex</span> 创建的。</p></li>
<li><p><i class="FIRSTTERM">转换处理</i>对分析器返回的数据结构进行修改和增补。</p></li>
</ul>
<div class="SECT2"><h2 class="SECT2"><a name="AEN61447">42.3.1. 分析器</a></h2>
<p>分析器必须检查(以纯 ASCII 文本方式到来的)查询字符串的语法。如果语法正确，则创建一个<i class="FIRSTTERM">分析树</i>并将之传回，否则，返回一个错误。实现分析器和词法器使用了著名的 Unix 工具 <span class="APPLICATION">yacc</span> 和 <span class="APPLICATION">lex</span></p>
<p><i class="FIRSTTERM">词法器</i>在文件 <tt class="FILENAME">scan.l</tt> 里定义，负责识别<i class="FIRSTTERM">标识符</i>和 <i class="FIRSTTERM">SQL 关键字</i>等。对于发现的每个关键字或者标识符都会生成一个<i class="FIRSTTERM">记号</i>并且传递给分析器。</p>
<p>分析器在文件<tt class="FILENAME">gram.y</tt>里定义并且包含一套<i class="FIRSTTERM">语法规则</i>和触发规则时执行的<i class="FIRSTTERM">动作</i>。动作代码(实际上是 C 代码)用于建立分析树。</p>
<p>文件 <tt class="FILENAME">scan.l</tt> 用 <span class="APPLICATION">lex</span> 转换成 C 源文件 <tt class="FILENAME">scan.c</tt> ，而 <tt class="FILENAME">gram.y</tt> 用 <span class="APPLICATION">yacc</span> 转换成 <tt class="FILENAME">gram.c</tt> 。在完成这些转换后，一个通用的 C 编译器就可以用于创建分析器。千万不要对生成的 C 源文件做修改，因为下一次调用 <span class="APPLICATION">lex</span> 或 <span class="APPLICATION">yacc</span> 时会把它们覆盖。</p>
<div class="NOTE">
<blockquote class="NOTE">
<p><b>【注意】</b>上面提到的转换和编译是使用跟随 PostgreSQL 发布的 <i class="FIRSTTERM">makefiles</i> 自动完成的。</p>
</blockquote>
</div>
<p>对 <span class="APPLICATION">yacc</span> 或者 <tt class="FILENAME">gram.y</tt> 里的语法规则的详细描述超出本文的范围。有很多关于 <span class="APPLICATION">lex</span> 和 <span class="APPLICATION">yacc</span> 的书籍和文档。你在开始研究 <tt class="FILENAME">gram.y</tt> 里给出的语法之前应该对 <span class="APPLICATION">yacc</span> 很熟悉，否则你是看不懂那里面的内容，理解不了发生了什么事情的。</p>
</div>
<div class="SECT2"><h2 class="SECT2"><a name="AEN61483">42.3.2. 转换处理</a></h2>
<p>分析器阶段只使用和 SQL 语法结构相关的固定规则创建一个分析树。它不会查找任何系统表，因此就不可能理解请求查询里面的详细的语意。在分析器技术之后，<i class="FIRSTTERM">转换处理</i>接受分析器传过来的分析树然后做进一步处理，解析哪些查询中引用了哪个表、哪个函数、哪个操作符的语意。所生成的表示这个信息的数据结构叫做<i class="FIRSTTERM">查询树</i>。</p>
<p>把裸分析和语意分析分成两个过程的原因是系统表查找只能在一个事务中进行，而不想在一接收到查询字符串就发起一个事务。裸分析阶段已经足够可以标识事务控制命令(<tt class="COMMAND">BEGIN</tt>, <tt class="COMMAND">ROLLBACK</tt> 等)，并且这些东西不用任何进一步的分析就可以执行。一旦知道正在处理一个真正的查询(比如 <tt class="COMMAND">SELECT</tt> 或 <tt class="COMMAND">UPDATE</tt>)，就可以发起一个事务了(如果还没开始这么一个)。只有这个时候可以调用转换处理。</p>
<p>转换处理生成的查询树结构上在很大程度上类似于裸分析树，但是在细节上有很多区别。比如，在分析树里的 <tt class="STRUCTNAME">FuncCall</tt> 节点代表那些看上去像函数调用的东西。根据引用的名字是一个普通函数还是一个聚集函数，这个可能被转换成一个 <tt class="STRUCTNAME">FuncExpr</tt> 或 <tt class="STRUCTNAME">Aggref</tt> 节点。同样，有关字段和表达式结果的具体数据类型也添加到查询树中。</p>
</div>
</div>
<div>
<hr align="LEFT" width="100%">
<table summary="Footer navigation table" width="100%" border="0" cellpadding="0" cellspacing="0">
<tr><td width="33%" align="left" valign="top"><a href="connect-estab.html" accesskey="P">后退</a></td><td width="34%" align="center" valign="top"><a href="index.html" accesskey="H">首页</a></td><td width="33%" align="right" valign="top"><a href="rule-system.html" accesskey="N">前进</a></td></tr>
<tr><td width="33%" align="left" valign="top">连接是如何建立起来的</td><td width="34%" align="center" valign="top"><a href="overview.html" accesskey="U">上一级</a></td><td width="33%" align="right" valign="top">PostgreSQL 规则系统</td></tr>
</table>
</div>
</body></html>